#include <SDL.h>
#include <iostream>


#include "timemanager.h"
#include "timer.h"
#include <list>

using namespace std;

TimeManager* TimeManager::m_self=0;
volatile unsigned long TimeManager::tick=0;

TimeManager::TimeManager():timetick(0),frameskip(0),max_frameskip(0),\
										 totalframeskip(0),max_fps(0),graphic_tick(0),\
										 logic_tick(0),old_tick(0)
{
	m_self=this;
}

TimeManager::~TimeManager()
{
	m_self=0;
}

TimeManager& TimeManager::self()
{
	if(m_self==0)
		new TimeManager();

	return *m_self;
}

bool TimeManager::exists()
{
	return m_self!=0;
}

bool TimeManager::init(int atimetick)
{
	max_fps=60;
	timetick=atimetick;
	max_frameskip=5;
	if(!(timerID=SDL_AddTimer(timetick,tickCount,NULL)))
		return -1;

	Timer::setTimeManager(this);

	return 0;
}

void TimeManager::update()
{
	if(tick-old_tick>=ticksPerSecond())
	{
		cout<<"fps: "<<graphic_tick<<" fs: "<<totalframeskip<<endl;
		graphic_tick=0;
		totalframeskip=0;
		old_tick=tick;
	}

	list<Timer*>::iterator it;
	list<Timer*>::iterator tim;

    if(!to_add.empty())
    {
		//Borramos los timers para eliminar
		for(it=to_add.begin();it!=to_add.end();it++)
		{
            tim=find(to_del.begin(),to_del.end(),*it);
            // Si no esta en la lista de eliminar
            if(tim==to_del.end())
            {
                tim=find(timers.begin(),timers.end(),*it);
                // Si esta en la lista principal
                if(tim==timers.end())
                    timers.push_back(*it);
            }
		}
    }
    to_add.clear();
	if(!to_del.empty())
	{
		//Borramos los timers para eliminar
		for(it=to_del.begin();it!=to_del.end();it++)
		{
			tim=find(timers.begin(),timers.end(),*it);
            if(tim!=timers.end())
				timers.erase(tim);
		}
	}
	to_del.clear();
	
	for(tim=timers.begin();tim!=timers.end();tim++)
    {
		(*tim)->update();
    }
}

void TimeManager::shutdown()
{
	SDL_RemoveTimer(timerID);
}

void TimeManager::addTimer(Timer *t)
{
	to_add.push_back(t);
}

void TimeManager::delTimer(Timer *t)
{
	to_del.push_back(t);
}

Uint32 TimeManager::tickCount(Uint32 interval,void *parameter)
{
	TimeManager::tick++;
	return interval;
}

bool TimeManager::isLogictick()
{
	if(logic_tick<=tick)
	{
		logic_tick++;
		return true;
	}
	else
		return false;
}

bool TimeManager::isGraphictick()
{
	//Si el juego no va retrasado
	if(logic_tick>tick || frameskip>max_frameskip)
	{
		//Si hay un gran desfase entre lo grafico y la logica
		//normalizamos la situacion
		if(frameskip>max_frameskip)
			logic_tick=tick;

		//Si llevo mas frames que los que deberia llevar en el tick actual
		//paro para no sobrecargar la CPU
		if(graphic_tick>=((float)max_fps/ticksPerSecond())*(logic_tick-old_tick))
		{
			SDL_Delay(10);
			return false;
		}
		else
		{
			graphic_tick++;
			frameskip=0;
			return true;
		}
	}
	else
	{
		frameskip++;
		totalframeskip++;
		return false;
	}
}
